﻿#include "EditorWindowGroupModel.h"
#include "Object/NewObject.h"
#include "Framework/Editor.h"
#include "Project/ProjectModel.h"
#include "PageArea/EditorPageAreaManagerModel.h"
#include "Pages/TextFile/EditorTextFilePageModel.h"
#include "Pages/EmptyAsset/EditorEmptyAssetPageModel.h"
#include "Window/EditorMainWindowModel.h"
#include "Window/EditorSubwindowModel.h"

#include "File/FileUtils.h"
#include "Asset/AssetSubsystem.h"
#include "Texture/Texture2D.h"
#include "Mesh/StaticMesh.h"
#include "Scene/Scene.h"
#include "Material/Material.h"
#include "Audio/Audio.h"
#include "MaterialGraph/MaterialGraphModel.h"
#include "Pages/Mesh/EditorMeshPageModel.h"
#include "Pages/Texture/EditorTexturePageModel.h"
#include "Pages/Scene/EditorScenePageModel.h"
#include "Pages/Material/EditorMaterialPageModel.h"
#include "Pages/Audio/EditorAudioPageModel.h"

#include "Project/ProjectModel.h"

#include "Framework/Application.h"

static REditorWindowGroupModel*
    GEditorWindowGroupModel = nullptr;

REditorWindowGroupModel::REditorWindowGroupModel()
{
    GEditorWindowGroupModel=this;
}

void REditorWindowGroupModel::Initialize()
{
    GetEditor()->MakeSureInitialized<RProjectModel>();
    GetEditor()->GetSubsystem<RProjectModel>()
        ->OnProjectOpened.BindScript(
            this
            ,&REditorWindowGroupModel::CloseAllPages);
}

void REditorWindowGroupModel::Deinitialize()
{
    GEditorWindowGroupModel = nullptr;
}

REditorWindowGroupModel *REditorWindowGroupModel::Get()
{
    return GEditorWindowGroupModel;
}

void REditorWindowGroupModel::CreateAndShowMainWindow()
{
    if(MainWindow)
    {
        //window already created
        return;
    }
    CreateMainWindow();
}

void REditorWindowGroupModel::CreateMainWindow()
{
    assert(!MainWindow && "MainWindow already created");
    MainWindow = NewObject<REditorMainWindowModel>(this);
    RegisterWindow(MainWindow);
}

TSharedObjectPtr<REditorSubwindowModel> REditorWindowGroupModel::CreateSubwindow()
{
    auto Subwindow = NewObject<REditorSubwindowModel>(this);
    RegisterWindow(Subwindow);
    return Subwindow;
}

void REditorWindowGroupModel::RegisterWindow(TSharedObjectPtr<REditorWindowModel> Window)
{
    Windows.Add(Window);
    OnWindowRegistered.Broadcast(Window);
}

void REditorWindowGroupModel::UnregisterWindow(TSharedObjectPtr<REditorWindowModel> Window)
{
    Windows.Remove(Window);
    OnWindowUnregistered.Broadcast(Window);
}

TVector<TSharedObjectPtr<REditorWindowModel>> REditorWindowGroupModel::GetWindows() const
{
    return Windows;
}

void REditorWindowGroupModel::CloseWindow(TSharedObjectPtr<REditorWindowModel> Window)
{
    if(Window->GetClass() == REditorMainWindowModel::StaticClass())
    {
        //main window closed
        //exit application
        REditor::Get()->Exit();
    }

    UnregisterWindow(Window);
}

TSharedObjectPtr<REditorPageAreaManagerModel> REditorWindowGroupModel::GetFocusedPageAreaManager() const
{
    return FocusedPageAreaManager;
}

void REditorWindowGroupModel::FocusePageAreaManager(TSharedObjectPtr<REditorPageAreaManagerModel> InPageArea)
{
    if(FocusedPageAreaManager == InPageArea)
    {
        return;
    }

    // if(FocusedPageAreaManager)
    // {
    //     FocusedPageAreaManager->Unfocus();
    // }

    FocusedPageAreaManager = InPageArea;

    // if(FocusedPageAreaManager)
    // {
    //     FocusedPageAreaManager->Focus();
    // }
}

TSharedObjectPtr<REditorPageAreaModel> REditorWindowGroupModel::GetFocusedPageArea() const
{
    if(FocusedPageAreaManager)
    {
        return FocusedPageAreaManager->GetFocusedPageArea();
    }
    return nullptr;
}

TSharedObjectPtr<REditorPageModel> REditorWindowGroupModel::GetFocusedPage() const
{
    if(FocusedPageAreaManager)
    {
        return FocusedPageAreaManager->GetCurrentPage();
    }
    return nullptr;
}

void REditorWindowGroupModel::OpenPage(TSharedObjectPtr<REditorPageModel> Page)
{
    if(!FocusedPageAreaManager)
    {
        FocusedPageAreaManager = MainWindow->GetPageArea();
    }

    FocusedPageAreaManager->AddPageInDefaultArea(
        Page
        , true
    );
}

void REditorWindowGroupModel::ReplacePage(TSharedObjectPtr<REditorPageModel> OldPage, TSharedObjectPtr<REditorPageModel> NewPage)
{
    if(!FocusedPageAreaManager)
    {
        FocusedPageAreaManager = MainWindow->GetPageArea();
    }

    FocusedPageAreaManager->ReplacePage(OldPage,NewPage);
}

void REditorWindowGroupModel::CloseAllPages()
{
    for(auto& Window:Windows)
    {
        Window->GetPageArea()->ClearAll();
    }
}

void REditorWindowGroupModel::OpenFile(const SPath &FilePath)
{
    TScriptDelegate<TSharedObjectPtr<REditorPageModel>()> CreatePageMethod;
    CreatePageMethod.BindLambda([this,FilePath](){
        return CreatePage(FilePath);
    });
   
    OpenPage(FilePath.ToString(),CreatePageMethod);
}

void REditorWindowGroupModel::OpenPage(const CString &PageID, TScriptDelegate<TSharedObjectPtr<REditorPageModel>()> CreatePageMethod)
{
    //open file in a new page
    //if file is already opened, bring the page front
    //if file is not opened, create a new page
    
    if(FocusedPageAreaManager)
    {
        auto PageArea=FocusedPageAreaManager->GetFocusedPageArea();
        if(PageArea)
        {
            auto PageIndex=PageArea->FindPage(PageID);
            if(PageIndex!=-1)
            {
                //file already opened, bring the page front
                PageArea->BringPageFront(PageIndex);
                return;
            }
        }
    }

    auto Page= CreatePageMethod.Broadcast();
    OpenPage(Page);
}

void REditorWindowGroupModel::ReopenPage(TSharedObjectPtr<REditorPageModel> InOpenedPage)
{
    auto Page=CreatePage(InOpenedPage->GetFilePath());
    ReplacePage(InOpenedPage,Page);
}

TSharedObjectPtr<REditorPageModel> REditorWindowGroupModel::CreatePage(const SPath &FilePath)
{
    if(FilePath.IsAssetFile())
    {
        auto FileData=SFileUtils::ReadToBinary(FilePath);

        if(FileData.Empty())
        {
            //use default empty asset page
            return REditorEmptyAssetPageModel::Create(FilePath);
        }
        else
        {
            auto AssetPackage=REditor::Get()->GetSubsystem<RProjectModel>()->GetAssetPackage().GetValue();
            
            CString PathInPackage=SAssetPath::AbstractFolderPathInPackage(
                AssetPackage.Path
                ,FilePath
            );

            auto Objects=RAssetSubsystem::Get()->LoadAssetWithEditInfo(
                FileData
                ,AssetPackage
                ,PathInPackage
            );

            auto Object=Objects.First;
            auto EditInfoObject=Objects.Second;

            if(Object)
            {
                if(Object->IsA<RTexture2D>())
                {
                    //use texture page
                    return REditorTexturePageModel::Create(FilePath,Object);
                }
                else if(Object->IsA<RStaticMesh>())
                {
                    //use material page
                    return REditorMeshPageModel::Create(FilePath,Object);
                }
                else if(Object->IsA<RScene>())
                {
                    //use scene page
                    return REditorScenePageModel::Create(FilePath,Object);
                }
                else if(Object->IsA<RMaterial>())
                {
                    //use material page
                    return REditorMaterialPageModel::Create(FilePath,Object,EditInfoObject);
                }
                else if(Object->IsA<RAudio>())
                {
                    //use audio page
                    return REditorAudioPageModel::Create(FilePath,Object);  
                }
            }
            
            //不支持的类型，使用默认空白页
            return REditorEmptyAssetPageModel::Create(FilePath);

        }
        
    }
    else
    {
        //use default text file page
        return REditorTextFilePageModel::Create(FilePath);
    }
}


SPath REditorWindowGroupModel::GetCurrentFilePath() const
{
    auto FocusedPage=GetFocusedPage();
    if(FocusedPage)
    {
        return FocusedPage->GetFilePath();
    }
    return SPath();
}

void REditorWindowGroupModel::NotifyCurrentPageChanged()
{
    auto FocusedPage=GetFocusedPage();

    OnCurrentPageChanged.Broadcast(GetFocusedPage());

    if(FocusedPage)
    {
        OnPageFocusedObjectChanged(FocusedPage->GetFocuseObject());
    }
    else
    {
        OnPageFocusedObjectChanged(nullptr);
    }
}

TSharedObjectPtr<RObject> REditorWindowGroupModel::GetFocusedObject() const
{
    auto FocusedPage=GetFocusedPage();
    if(FocusedPage)
    {
        return FocusedPage->GetFocuseObject();
    }
    return nullptr;
}

void REditorWindowGroupModel::NotifyFocusedObjectChanged()
{
    OnPageFocusedObjectChanged(GetFocusedObject());
}

// void REditorWindowGroupModel::OnPageFocusedObjectChanged(TSharedObjectPtr<REditorPageModel> InPage, TSharedObjectPtr<RObject> InObject)
// {
//     if(InPage==GetFocusedPage())
//     {
//         OnPageFocusedObjectChanged(InObject);
//     }
// }

void REditorWindowGroupModel::OnPageFocusedObjectChanged(TSharedObjectPtr<RObject> InObject)
{
    if(FormerFocusedObject!=InObject)
    {
        FormerFocusedObject=InObject;
        OnFocusedObjectChanged.Broadcast(InObject);
    }
}
